hal.script.Import("exp.Pager");
hal.script.Import("exp.Branch");
hal.Create.Class(null, "exp.TreeNode", null, "exp.Tree", {
    init: function(container, props) {
        this.branchAngle = 30;
        this.branchColorAtv = "blue";
        this.branchColorIatv = "gray";
        
        this._labelAngle = [];
        for (var i = 0; i < 360 / this.branchAngle; i++) {
            this._labelAngle[i] = this.branchAngle - i * this.branchAngle;
            if (this._labelAngle[i] < 0) this._labelAngle[i] += 360;
        }

        this.parentBranch = null;
        this.treeRadius = 100;
        this.pageSize = 4;
        this.timeUnit = 1;
        this.activeBranch = -1;

        exp.TreeNode.prototype.init.apply(this, [container, props]);
        this.container = container;
        //this.setTreeEvents();

        this.createPager();
    },
    createPager: function() {
        if (!exp.Tree.pager) {
            exp.Tree.pager = new exp.Pager(this.canvas.parentNode, {
                cssText: "position:absolute;z-index: 9999;width:90%;height:19px;corlor:purple;top:0px;left:5%;font-size:1em;"
            });

            exp.Tree.pager.show(false);
            exp.Tree.pager.addListener("ongonext", function() {
                var node = exp.Tree.pager.currentNode;
                if (node.currentPage >= node.numberOfPage - 1) return;
                node.doSelectNode(node, 1);
            });
            exp.Tree.pager.addListener("ongoprev", function() {
                var node = exp.Tree.pager.currentNode;
                if (node.currentPage <= 0) return;
                node.doSelectNode(node, -1);
            });
        }
    },

    getNodeAngle: function(index) {
        return (index - 1) * this.branchAngle; //30;
    },
    setProp: function(p, value) {
        this[p] = value;
        switch (p) {
            case "childDatas":
                this.childDatas = value;
                break;
            case "left":
            case "top":
                var delta = (!isEmpty(this.radius)) ? this.radius : 0; //(!isEmpty(des.radius)) ? des.radius:0;
                this.canvas.style[p] = Math.floor(this[p] - delta) + "px";
                for (var i = 0; i < this.branches.length; i++)
                    if (this.branches[i])
                    this.branches[i].updateNodePos();
                break;
            default:
                exp.TreeNode.prototype.setProp.apply(this, [p, value]);
                break;
        }
    },
    show: function(flag) {
        if (flag == "false") {
            for (var i = 0; i < this.branches.length; i++)
                this.branches[i].show(flag);
        }
        exp.TreeNode.prototype.show.apply(this, [flag]);
    },

    drawIcon: function(iconType) {
        this.branches = [];
        exp.TreeNode.prototype.drawIcon.apply(this, [iconType]);
    },
    setIcon: function(iconType) {
        exp.TreeNode.prototype.setIcon.apply(this, [iconType]);
        if (this.activeBranch > -1) {
            this.branches[this.activeBranch].setProps({ treeRadius: this.treeRadius });
        }
    },
    addBranch: function(i, realIndex) {
        if (this.branches[i]) {
            this.canvas.removeChild(this.branches[i].canvas);
        }
        if (!this.childDatas[realIndex])
            return;
        var data = this.childDatas[realIndex];
        data.nodeIndex = i;
        data.imgPath = this.imgPath;
        this.branches[i] = new exp.Branch(this, data);
        return this.branches[i];
    },
    removeBranch: function(i) {
        /*this.canvas.removeChild(this.branches[i].canvas);
        this.branches[i].node.canvas.parentNode.removeChild(this.branches[i].node.canvas);
        this.branches[i] = null;*/
    },
    setBranch: function(index, props) { },

    doSelectNode: function(node, dir, justOpenFlag) {
        var br = node.parentBranch;
        //if (node.iconType.indexOf("selected") >= 0) return; // Commented for paging functionality
        if (isEmpty(dir)) dir = 1;

        if (br && br.parentTree && br.parentTree.expandEffect && br.parentTree.expandEffect.actionStatus == "onrun")
            return;
        var noSiblingSelected = false;
        var ef = this.selectEffect = new exp.ParallelMotions();
        if (br && justOpenFlag != true) {
            var t = br.parentTree.activeBranch;
            if (t < 0)
                noSiblingSelected = true;
            else if (t != br.nodeIndex) {
                br.parentTree.branches[t].setClose(false); // Close current active node
                br.parentTree.activeBranch = br.nodeIndex; // Set new active node
                br.setActive(false);

                ef.addChild(br.parentTree.branches[t].closeEffect);
                ef.addChild(br.activeEffect);
                br.activeEffect.addListener("onstop", function() {
                    br.parentTree.doOpenAll(br.node, dir, true); // Auto expand new active node 
                    this.removeListener("onstop", arguments.callee);
                });
                ef.start();
                return;
            }
            br.setActive(false);
            br.parentTree.activeBranch = br.nodeIndex;
            ef.addChild(br.activeEffect);
        }

        // Open new nodes
        node.doOpenAll(node, dir, false);
        ef.addChild(node.openAllEffect);
        ef.start();
    },
    doOpenAll: function(node, dir, flag) {
        var ef = this.openAllEffect = new exp.ParallelMotions();
        if (!(node.childDatas && node.childDatas.length > 0))
            return;

        if (isEmpty(dir)) dir = 0;

        if (node.childDatas) {
            if (node.iconType.indexOf("passed") > 0) {
                if (!isEmpty(node.currentPage)) // For paging
                    node.currentPage = node.currentPage - 1;
                else {
                    node.currentPage = -1;
                    node.numberOfPage = Math.floor(node.childDatas.length / node.pageSize);
                }
            }
            if (isEmpty(node.currentPage)) { // Open first page                
                node.currentPage = 0;
                node.numberOfPage = Math.floor(node.childDatas.length / node.pageSize);
                if (node.childDatas.length > node.numberOfPage * node.pageSize)
                    node.numberOfPage++;
                node.doOpenNewPage(node, 0, false);
                ef.addChild(node.openCurrentPageEffect);

                var it = node.iconType.split("_");
                node.setProps({ labelAngle: 90, iconType: (it[0] + "_L_" + it[2] + "_selected") });
                node.activeBranch = -1;
            }
            else if (node.numberOfPage > 1 || node.iconType.indexOf("passed") > 0) {
                node.doClose(false, false);
                ef.addChild(node.closeEffect);
                node.closeEffect.addListener("onstop", function(sender) {
                    node.doOpenNewPage(node, dir, true);
                    sender.removeListener("onstop", arguments.callee);
                });
                var it = node.iconType.split("_");
                node.setProps({ labelAngle: 90, iconType: (it[0] + "_L_" + it[2] + "_selected") });
                node.activeBranch = -1;
            }
        }
        if (flag == true)
            ef.start();
    },
    doOpenNewPage: function(node, dir, runNow) {
        var ef = node.openCurrentPageEffect = new exp.ParallelMotions();
        node.currentPage += dir;
        if (node.currentPage > node.numberOfPage - 1) node.currentPage = 0;
        if (node.currentPage < 0) node.currentPage = node.numberOfPage - 1;

        // Get start and stop node for current page
        var start = node.currentPage * node.pageSize;
        var stop = start + node.pageSize - 1;
        if (stop > node.childDatas.length - 1)
            stop = node.childDatas.length - 1;

        // Draw all nodes
        for (var i = start; i <= stop; i++) {
            node.addBranch(i - start, i);
            if (node.branches[i - start]) {
                node.branches[i - start].setExpand();
                ef.addChild(node.branches[i - start].expandEffect);
            }
        }

        ef.addListener("onstop", function() {
            //node.broadcast("onopenpage");
            if (node.numberOfPage > 1) {
                exp.Tree.pager.show(true);
                exp.Tree.pager.currentNode = node;
                exp.Tree.pager.setProp("currentPage", node.currentPage + 1);
                exp.Tree.pager.setProp("numberOfPage", node.numberOfPage);
                node.canvas.appendChild(exp.Tree.pager.canvas);
                //exp.Tree.pager.setProps({ top: node.top - Math.floor(3 * node.radius / 4), left: node.left - 3 * node.radius / 4, width: node.radius * 1.5, fontSize: node.fontSize });
            }
            else
                exp.Tree.pager.show(false);
        });
        if (runNow)
            ef.start();
    },
    doClose: function(runFlag, allFlag) {
        var ef = this.closeEffect = new exp.ParallelMotions();
        for (var i = 0; i < this.branches.length; i++) {
            if (this.branches[i]) {
                this.branches[i].setClose(false, true);
                ef.addChild(this.branches[i].closeEffect);
            }
        }
        if (allFlag == true) {
            if (this.parentBranch)
                var pa = this.parentBranch.parentTree;
            else
                var pa = this;
            this.setAnimation({ left: pa.left, top: pa.top, radius: 1, fontSize: 1 }, pa.timeUnit);
            ef.addChild(this.animation);

            var self = this;
            ef.addListener("onstop", function(sender) {
                if (self.canvas.parentNode) {
                    if (self.label && self.label.parentNode)
                        self.label.parentNode.removeChild(self.label); //self.node.show(false);
                    self.canvas.parentNode.removeChild(self.canvas); //self.node.show(false);
                }
                sender.removeListener("onstop", arguments.callee);
            });
        }
        if (runFlag)
            ef.start();
    },
    doZoom: function(rate) {
        if (this.animation.actionStatus == "onrun" || this.isLocked == true)
            return;

        this.zoomRate = this.zoomRate * rate;
        var ef = this.zoomEffect = new exp.ParallelMotions();
        // Tree's target props
        ef.zoomDes = { treeRadius: this.treeRadius * rate, radius: this.radius * rate, fontSize: Math.round(this.getProp("fontSize") * rate), left: this.left, top: this.top };
        if (this.parentBranch) {
            var pb = this.parentBranch, pa = this.parentBranch.parentTree;
            var pades = pa.zoomEffect.zoomDes, pbdes = pb.zoomEffect.zoomDes;
            var pos = this.parentBranch.getNodePos(this.nodeIndex, pades.left || pa.left, pades.top || pa.top, pbdes.treeRadius || pb.treeRadius);
            ef.zoomDes.left = pos.left;
            ef.zoomDes.top = pos.top;
        }

        for (var i = 0; i < this.branches.length; i++) {
            if (this.branches[i]) {
                this.branches[i].setZoom(rate, false);
                ef.addChild(this.branches[i].zoomEffect);
            }
        }
        this.setAnimation(ef.zoomDes, this.timeUnit);
        this.zoomEffect.addChild(this.animation);

        var self = this;
        this.zoomEffect.addListener("onstart", function(sender) {
            sender.removeListener("onstart", arguments.callee);
        });
        this.zoomEffect.addListener("onstop", function(sender) {
            self.setIcon(self.iconType);
            sender.removeListener("onstop", arguments.callee);
        });
        // Lock this when animation runs
        this.applyLocker(this.zoomEffect);

        // If this is root
        if (!this.parentBranch)
            this.zoomEffect.start();
    },

    onSelected: function() {
        if (this.canNotClick())
            return;
        if (this.parentBranch)
            this.parentBranch.parentTree.doSelectNode(this);
        else
            this.doSelectNode(this);
    },

    canNotClick: function() {
        var test = (this.animation.actionStatus == "onrun") ||
           (this.parentBranch && this.parentBranch.animation.actionStatus == "onrun") ||
           this.isLocked == true;
        if (test) return test;
        if (this.parentBranch) {
            for (var i = 0; i < this.parentBranch.parentTree.branches.length; i++) {
                if (this.parentBranch.parentTree.branches[i] && this.parentBranch.parentTree.branches[i].animation.actionStatus == "onrun")
                    return true;
            }
        }
        return false;
    },

    setLock: function(flag, fromRoot) {
        if (this.parentBranch && !fromRoot) {
            this.parentBranch.parentTree.setLock(flag, false);
            return;
        }
        this.isLocked = (flag == false) ? false : true; // Lock root
        for (var i = 0; i < this.branches.length; i++) // lock all children
            if (this.branches[i])
            this.branches[i].node.setLock(flag, true);
    },

    applyLocker: function(motion) {
        var self = this;
        motion.addListener("onstart", function(sender) { self.setLock(true); sender.removeListener("onstart", arguments.callee); });
        motion.addListener("onstop", function(sender) { self.setLock(false); sender.removeListener("onstop", arguments.callee); });
    }
});